#include "../include/network.h"
#include "../include/command.h"
#include "../include/threadpool.h"
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

// 客户端任务结构
typedef struct ClientTask {
    int client_fd;
    char* data;
    size_t data_len;
    Cache* cache;
} ClientTask;

// 处理客户端命令的任务函数
void handle_client_command(void* arg) {
    ClientTask* task = (ClientTask*)arg;
    if(!task) return;
    
    // 解析命令
    char response[1024];
    char* data = task->data;
    
    // 移除换行符
    size_t len = strlen(data);
    if(len > 0 && (data[len-1] == '\n' || data[len-1] == '\r')) {
        data[len-1] = '\0';
    }
    if(len > 1 && (data[len-2] == '\r')) {
        data[len-2] = '\0';
    }
    
    // 执行命令
    command_dispatch(data, response, sizeof(response), task->cache);
    
    // 发送响应
    char* full_response = malloc(strlen(response) + 3);
    sprintf(full_response, "%s\r\n", response);
    
    send(task->client_fd, full_response, strlen(full_response), 0);
    
    // 清理
    free(full_response);
    free(task->data);
    free(task);
}

/**
 * 启动服务器，初始化socket、epoll等
 * @param server 服务器指针
 * @param port 监听端口
 * @param threadpool 线程池指针
 * @param cache 缓存指针
 * @return 0 成功，-1 失败
 */
int network_server_start(NetworkServer* server, int port, void* threadpool, void* cache)
{
    // 检查参数
    if(!server || !threadpool || !cache)  return -1;
    // 初始化服务器结构体
    server->port = port;
    server->threadpool = (ThreadPool*)threadpool;
    server->cache = (Cache*)cache;
    // 初始化socket tcp协议
    server->listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(server->listen_fd == -1)
    {
        perror("Failed to create socket");
        return -1;
    }
    // 设置socket选项 端口复用 不用等待2MSL时间（TIME_WAIT）
    int optval = 1;
    if(setsockopt(server->listen_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
    {
        perror("Failed to set socket option");
        close(server->listen_fd);
        return -1;
    }
    // 绑定地址
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(server->listen_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    {
        perror("Failed to bind address");
        close(server->listen_fd);
        return -1;
    }
    // 监听
    if(listen(server->listen_fd, LISTEN_BACKLOG) == -1)
    {
        perror("Failed to listen");
        close(server->listen_fd);
        return -1;
    }
    // 初始化epoll
    // 创建epoll实例 参数为0 表示创建一个epoll实例
    server->epoll_fd = epoll_create1(0);
    if(server->epoll_fd == -1)
    {
        perror("Failed to create epoll instance");
        close(server->listen_fd);
        return -1;
    }
    // 设置监听socket为非阻塞
    // F_GETFL 获取文件描述符的当前标志
    // F_SETFL 设置文件描述符的标志 O_NONBLOCK 非阻塞
    int flags = fcntl(server->listen_fd, F_GETFL, 0);
    fcntl(server->listen_fd, F_SETFL, flags | O_NONBLOCK);
    
    // 添加监听socket到epoll，使用边缘触发
    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET;  // 边缘触发
    ev.data.fd = server->listen_fd;
    if(epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, server->listen_fd, &ev) == -1)
    {
        perror("Failed to add listen socket to epoll");
        close(server->listen_fd);
        close(server->epoll_fd);
        return -1;
    }
    // 返回成功
    return 0;
}

/**
 * 处理新连接
 * @param server 服务器指针
 */
void handle_accept(NetworkServer* server)
{
    while(1)
    {
        // 接受新连接
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int client_fd = accept(server->listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
        if(client_fd == -1)
        {
            // EAGAIN 表示没有更多新连接
            // EWOULDBLOCK 表示读取被阻塞
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有更多新连接，退出循环
                break;
            } else {
                perror("Failed to accept");
                break;
            }
        }
        
        // 设置客户端socket为非阻塞
        // F_GETFL 获取文件描述符的当前标志
        // F_SETFL 设置文件描述符的标志 O_NONBLOCK 非阻塞
        int flags = fcntl(client_fd, F_GETFL, 0);
        fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
        
        // 添加到epoll实例中，使用边缘触发
        struct epoll_event ev;
        ev.events = EPOLLIN | EPOLLET;  // 边缘触发
        ev.data.fd = client_fd;
        if(epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1)
        {
            perror("Failed to add client socket to epoll");
            close(client_fd);
            continue;
        }
        // 打印新连接信息
        // inet_ntoa 将网络字节序的ip地址转换为点分十进制字符串
        // ntohs 将网络字节序的端口号转换为主机字节序的端口号
        printf("New connection from %s:%d, fd=%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);
    }
}

/**
 * 服务器主循环（epoll事件循环）
 * @param server 服务器指针
 */
void network_server_run(NetworkServer* server)
{
    // 初始化epoll事件数组
    // 数组创建在栈区就可以了
    struct epoll_event events[MAX_EVENTS];
    while(1)
    {
        // 等待事件发生
        // 阻塞等待，直到有事件发生
        int nfds = epoll_wait(server->epoll_fd, events, MAX_EVENTS, -1);
        if(nfds == -1)
        {
            perror("Failed to wait for events");
            continue;
        }
        // 处理事件
        for(int i = 0; i < nfds; i++)
        {
            // 判断事件类型
            if(events[i].data.fd == server->listen_fd)
            {
                // 处理新链接
                handle_accept(server);
            }
            else
            {
                // 处理客户端数据
                handle_client_data(server, events[i].data.fd);
            }
        }
    }
}

// 处理客户端数据（读、解析、投递任务）
void handle_client_data(NetworkServer* server, int client_fd)
{
    char buffer[READ_BUFFER_SIZE];
    ssize_t bytes_read = 0;

    // epoll为边缘触发：循环读取所有数据
    // client_fd为非阻塞：直接读取，没有数据就返回
    while(1)
    {
        bytes_read = read(client_fd, buffer, sizeof(buffer) - 1);  // 留一个字节给 '\0'
        if(bytes_read == -1)
        {
            // EAGAIN 表示读取到文件末尾
            // EWOULDBLOCK 表示读取被阻塞
            if(errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 没有更多数据，退出循环
                break;
            }
            else if(errno == EINTR)
            {
                // 被信号中断，重试
                continue;
            }
            else
            {
                // 读取失败，关闭连接
                perror("Failed to read from client");
                close_client(server, client_fd);
                return;
            }
        }
        else if(bytes_read == 0)
        {
            // 客户端关闭连接
            printf("Client disconnected, fd=%d\n", client_fd);
            close_client(server, client_fd);
            return;
        }
        
        // 读取成功，处理数据
        // 添加字符串结束符
        buffer[bytes_read] = '\0';

        // 创建任务并投递到线程池
        ClientTask* task = malloc(sizeof(ClientTask));
        if(!task) {
            perror("Failed to allocate task");
            close_client(server, client_fd);
            return;
        }
        
        task->client_fd = client_fd;
        // 分配任务数据 + 1 是为了给 '\0' 留空间
        task->data = malloc(bytes_read + 1);
        if(!task->data) {
            perror("Failed to allocate task data");
            free(task);
            close_client(server, client_fd);
            return;
        }
        // 复制数据到任务数据
        strcpy(task->data, buffer);
        // 添加字符串结束符
        task->data[bytes_read] = '\0';
        // 设置数据长度
        task->data_len = bytes_read;
        // 设置缓存指针
        task->cache = server->cache;
        
        // 投递到线程池
        if(threadpool_add(server->threadpool, handle_client_command, task) != 0) {
            perror("Failed to add task to threadpool");
            free(task->data);
            free(task);
            close_client(server, client_fd);
            return;
        }
        
        // 数据处理完成，退出循环
        break;
    }
}

/**
 * 关闭客户端连接
 * @param client_fd 客户端文件描述符
 */
 void close_client(NetworkServer* server, int client_fd)
{
    // 关闭客户端连接
    close(client_fd);
    // 从epoll中移除
    epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
    // 打印关闭信息
    printf("Client disconnected, fd=%d\n", client_fd);
}

/**
 * 关闭服务器，释放资源
 * @param server 服务器指针
 */
void network_server_stop(NetworkServer* server)
{
    if(!server) return;
    // 关闭监听socket
    if(server->listen_fd != -1)
    {
        close(server->listen_fd);
        server->listen_fd = -1;
        printf("Closed listen socket\n");
    }
    // 关闭epoll实例
    if(server->epoll_fd != -1)
    {
        close(server->epoll_fd);
        server->epoll_fd = -1;
        printf("Closed epoll instance\n");
    }
    // 打印关闭信息
    printf("Server stopped on port %d\n", server->port);
}
